package com.lvhr.rpc.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.dialect.Props;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.StringJoiner;

public class ConfigUtils1 {
    private static final String BASE_NAME = "application";
    private static final boolean DEBUG = false; // 可通过系统参数控制

    public static <T> T loadConfig(Class<T> tClass) {
        return loadConfig(tClass, "", null, null);
    }

    public static <T> T loadConfig(Class<T> tClass, String prefix) {
        return loadConfig(tClass, prefix, null, null);
    }

    public static <T> T loadConfig(Class<T> tClass, String prefix, String environment) {
        return loadConfig(tClass, prefix, environment, null);
    }

    /**
     * 统一配置加载入口
     * @param tClass       目标配置类
     * @param prefix       配置前缀（Properties专用）
     * @param environment  环境标识
     * @param fileType     文件类型（默认自动推断）
     */
    public static <T> T loadConfig(Class<T> tClass, String prefix, String environment, String fileType) {
        String fileName = buildFileName(environment, fileType);

        // 自动识别文件类型
        String resolvedFileType = Optional.ofNullable(fileType)
                .orElseGet(() -> detectFileType(fileName));

        try {
            switch (resolvedFileType.toLowerCase()) {
                case "properties":
                    return loadPropertiesConfig(tClass, prefix, fileName);
                case "yml":
                case "yaml":
                    return loadYamlConfig(tClass, fileName);
                default:
                    throw new UnsupportedOperationException("Unsupported config file type: " + resolvedFileType);
            }
        } catch (IOException e) {
            throw new ConfigLoadException("Config load failed: " + fileName, e);
        }
    }

    private static String buildFileName(String environment, String fileType) {
        StringJoiner fileName = new StringJoiner("-", BASE_NAME, "")
                .setEmptyValue(BASE_NAME);

        if (StrUtil.isNotBlank(environment)) {
            fileName.add(environment);
        }

        String suffix = StrUtil.isBlank(fileType) ? "" : "." + fileType;
        return fileName + suffix;
    }

    private static String detectFileType(String fileName) {
        if (fileName.endsWith(".yml") || fileName.endsWith(".yaml")) {
            return "yaml";
        }
        if (fileName.endsWith(".properties")) {
            return "properties";
        }
        throw new IllegalArgumentException("Cannot detect file type from: " + fileName);
    }

    private static <T> T loadPropertiesConfig(Class<T> tClass, String prefix, String fileName) throws IOException {
        Props props = new Props(fileName, StandardCharsets.UTF_8);

        if (DEBUG) {
            props.forEach((k, v) -> System.out.printf("[Config] %s = %s%n", k, v));
        }

        return props.toBean(tClass, prefix);
    }

    private static <T> T loadYamlConfig(Class<T> tClass, String fileName) throws IOException {
        Yaml yaml = new Yaml(new Constructor(tClass, new LoaderOptions()));
        try (InputStream in = getResourceAsStream(fileName)) {
            return yaml.load(in);
        }
    }

    private static InputStream getResourceAsStream(String fileName) {
        InputStream in = ConfigUtils.class.getClassLoader().getResourceAsStream(fileName);
        if (in == null) {
            throw new ResourceNotFoundException("Config file not found: " + fileName);
        }
        return in;
    }

    // 自定义异常类
    public static class ConfigLoadException extends RuntimeException {
        public ConfigLoadException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    public static class ResourceNotFoundException extends RuntimeException {
        public ResourceNotFoundException(String message) {
            super(message);
        }
    }
}
